/***************************************************************************/
/* NOTE:                                                                   */
/* This document is copyright (c) by Oz Solomonovich.  All non-commercial  */
/* use is allowed, as long as this document not altered in any way, and    */
/* due credit is given.                                                    */
/***************************************************************************/

// TabManagerWindow.cpp : implementation file
//
// This class is used to subclass DevStudio's windows.  It allows the 
// plug-in to monitor various messages that reach the window.
// TabManagerWindow is mainly responsible for moving and sizing the tabs
// window to it's appropriate position relative to the DevStudio window.
// The DevStudio window is also resized if needed.
//

//this line was inserted and notified to you
//I remove some function or porpert which this addin do not use
//it cound not be replaced by original file

#include "stdafx.h"
#include "TabBars.h"
#include "TabManagerWnd.h"
#include "TabBarWnd.h"
#include "Commands.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CTabManagerWindow

//##ModelId=431C34C6034C
CTabManagerWindow::CTabManagerWindow(IGenericWindow *pGWindow,
									 HWND hSubclassWindow) : m_bManaging(false), m_bMakeSpace(false), 
									 m_pGWindow(pGWindow), m_bUpdatePosted(false),
									 CSubclassWnd(hSubclassWindow)
{
	m_LastPos = m_Border = CRect(0, 0, 0, 0);
	UpdateTabSize();
	DoSubclass();
}

//##ModelId=431C34C603D9
CTabManagerWindow::~CTabManagerWindow()
{
	if (pGlobalActiveManager == this)
	{
		pGlobalActiveManager = NULL;
	}
	
	SetManaging(FALSE);
	DoUnsubclass();
	
	pGlobalTabs->UpdateTabs();
}


BEGIN_MESSAGE_MAP(CTabManagerWindow, CSubclassWnd)
//{{AFX_MSG_MAP(CTabManagerWindow)
ON_WM_WINDOWPOSCHANGING()
//}}AFX_MSG_MAP
ON_MESSAGE(WM_UPDATETABS, OnUpdateTabs)
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CTabManagerWindow message handlers

//##ModelId=431C34C700AC
void CTabManagerWindow::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos) 
{
	CSubclassWnd::OnWindowPosChanging(lpwndpos);
	
	if (m_bManaging)
	{
		CRect WndRect(lpwndpos->x,lpwndpos->y,lpwndpos->x + lpwndpos->cx,lpwndpos->y + lpwndpos->cy);
		
		if (lpwndpos->flags & (SWP_NOSIZE | SWP_NOMOVE))
		{
			CRect WndRectOld;
			GetWindowRect(WndRectOld);
			GetParent()->ScreenToClient(WndRectOld);
			if (lpwndpos->flags & SWP_NOSIZE)
			{
				WndRect.bottom = WndRect.top  + WndRectOld.Height();
				WndRect.right  = WndRect.left + WndRectOld.Width();
			}
			if (lpwndpos->flags & SWP_NOMOVE)
			{
				WndRect.OffsetRect(WndRectOld.left - lpwndpos->x,WndRectOld.top  - lpwndpos->y);
			}
		}
		
		if (WndRect != m_LastPos)
		{
			UpdateTabSizeAndPosition(WndRect);
			ASSERT(WndRect.left >= 0);
			ASSERT(WndRect.top >= 0);
// 			ASSERT(WndRect.right - WndRect.left <= 1024);            
			lpwndpos->x  = WndRect.left;
			lpwndpos->y  = WndRect.top;
			lpwndpos->cx = WndRect.right - WndRect.left;
			lpwndpos->cy = WndRect.bottom - WndRect.top;
			m_LastPos = WndRect;
		}
	}
}

// the message is used for delayed tab update
//##ModelId=431C34C700BB
LRESULT CTabManagerWindow::OnUpdateTabs(WPARAM wParam, LPARAM lParam)
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());
	
    ASSERT(pGlobalTabs);
    pGlobalTabs->UpdateTabs();
    m_bUpdatePosted = false;  // allow new posts
	
    return Default();
}


/////////////////////////////////////////////////////////////////////////////
// CTabManagerWindow attributes

// true/false - is this object is responsible for handling the tabs.
// We will always have two tab managers: the MDI tab manager and the 
// subclassed DevStudio window.  Only one of them actually manages the tabs
// (according to the user's preference).
//##ModelId=431C34C6038F
bool CTabManagerWindow::SetManaging(bool bManaging)
{
    if (m_hWnd == NULL)
        return m_bManaging;
	
    if (bManaging == m_bManaging)
        return m_bManaging;
	
    bool bOldVal = m_bManaging;
    m_bManaging = bManaging;
	
    UpdateTabSize();
    
    // add/remove the tabs
    if (m_bManaging)
    {
        ForceRedraw();
    }
    else
    {
        // reclaim space used by the tabs
        ReclameTabSpace();
    }
    
    return bOldVal;
}

// true  - the manager shrinks the window so that both the tabs and
//         the window occupy the original area of the window
// false - the tabs are aligned along side the window
//##ModelId=431C34C6039B
bool CTabManagerWindow::SetMakeSpace(bool bMakeSpace)
{
	if (m_bMakeSpace == bMakeSpace)
		return bMakeSpace;
	
	if (m_bManaging)
	{
		if (bMakeSpace)
		{
			ForceRedraw();
		}
		else
		{
			ReclameTabSpace();
		}
	}
	
	bool bOldVal = m_bMakeSpace;
	m_bMakeSpace = bMakeSpace;
	
	return bOldVal;
}

// Call SetBorder() to set an empty border around the tabs.  The tab
// window reads the border values from the tab manager and repaints
// accordingly.
//##ModelId=431C34C603B9
CRect CTabManagerWindow::SetBorder(CRect Border)
{
	CRect OldBorder = m_Border;
	
	if (Border != m_Border)
	{
		bool bOldManaging = SetManaging(false);
		m_Border = Border;
		UpdateTabSize();
		SetManaging(bOldManaging);
	}
	
	return OldBorder;
}


/////////////////////////////////////////////////////////////////////////////
// CTabManagerWindow operations

//##ModelId=431C34C603D8
void CTabManagerWindow::PostUpdateMessage()
{
	// make sure we don't have multiple update messages in the queue if we
	// hadn't updated yet:
	if (!m_bUpdatePosted)
	{
		m_bUpdatePosted = true;
		
		// post a message to ourselves
		PostMessage(WM_UPDATETABS);
	}
}


/////////////////////////////////////////////////////////////////////////////
// CTabManagerWindow protected operations

// Checks if there are as many tabs as windows, and updates if needed.
// Useful in cases where DevStudio removes it's own undocked windows (such
// as Disassembly or Output), since we get no notification of it, and must
// check for it somehow
//##ModelId=431C34C7004E
void CTabManagerWindow::CheckTabCount()
{
	long                               cWindows;
	CComPtr<IDispatch>                 pDisp;
	CComQIPtr<IWindows, &IID_IWindows> pWindows;
	
	ASSERT(pGlobalTabs);
	
	pGlobalTabs->m_pApplication->get_Windows(&pDisp);
	pWindows = pDisp;
	pDisp = NULL;
	pWindows->get_Count(&cWindows);
	if (pGlobalTabs->m_TabCtrl.GetItemCount() != cWindows)
	{
		pGlobalTabs->UpdateTabs();
	}
}

//##ModelId=431C34C7005D
void CTabManagerWindow::ForceRedraw()
{
	// we want to make sure the OnWindowPosChanging handler is called
	CRect WndRect;
	GetWindowRect(&WndRect);
	GetParent()->ScreenToClient(&WndRect);
	MoveWindow(WndRect, TRUE);
}

//##ModelId=431C34C7005E
void CTabManagerWindow::ReclameTabSpace()
{
	if (m_bMakeSpace)
	{
		CRect WndRect;
		GetWindowRect(&WndRect);
		GetParent()->ScreenToClient(&WndRect);
		
		if (cfg_iOrientation == soTop)
		{
			WndRect.top -= m_iTabHeight;
		}
		else
		{
			WndRect.bottom += m_iTabHeight;
		}
		
		MoveWindow(WndRect, TRUE);
	}
}

//##ModelId=431C34C7005F
void CTabManagerWindow::UpdateTabSizeAndPosition(CRect& WndRect)
{
	CRect TabsRect;
	
	if (!CalcTabsPosition(WndRect, TabsRect, SnapOrientations(cfg_iOrientation)))
		return;
	
	UpdateTabSize();
	
	pGlobalTabs->GetParent()->ScreenToClient(&TabsRect);
	ASSERT(TabsRect.bottom >= TabsRect.top);    
	ASSERT(TabsRect.right >= TabsRect.left);
	pGlobalTabs->SetWindowPos(&wndBottom,TabsRect.left,TabsRect.top, 
		TabsRect.right - TabsRect.left,TabsRect.bottom - TabsRect.top, SWP_DRAWFRAME);
	
	// force redraw
	pGlobalTabs->RedrawWindow();     
	pGlobalTabs->ShowWindow(SW_SHOW);
}

// TabsRect is returned in screen coordinates
//##ModelId=431C34C7008D
bool CTabManagerWindow::CalcTabsPosition(CRect &WndRect, CRect &TabsRect,SnapOrientations o) const
{
	if (WndRect.top == WndRect.bottom)
		return false;
	
	CSize szTabs = CalcTabsSize(o);
	
	TabsRect = WndRect;
	
	if(o == soTop)
	{
		if (m_bMakeSpace) 
			WndRect.top += szTabs.cy;
		else
			TabsRect.top -= szTabs.cy;
		
		TabsRect.bottom = TabsRect.top + szTabs.cy;
	}
	else
	{
		if (m_bMakeSpace) 
			WndRect.bottom -= szTabs.cy;
		else
			TabsRect.bottom += szTabs.cy;
		
		TabsRect.top = TabsRect.bottom - szTabs.cy;
	}
	
	GetParent()->ClientToScreen(&TabsRect);
	
	return true;
}

//##ModelId=431C34C7007E
CSize CTabManagerWindow::CalcTabsSize(SnapOrientations o) const
{
	CSize sz(0,0);;
	
	if (pGlobalTabs != NULL)
	{
		int iMinHeight = pGlobalTabs->m_iMinHeight;
		
		sz.cy = TAB_HEIGHT + iMinHeight; 
		
		if (o == soTop || o == soBottom)
		{
			sz.cy += m_Border.left + m_Border.right;// + 4;
			sz.cx = 0;
		}
		
		ASSERT(sz.cx >= 0);
		ASSERT(sz.cy >= 0);
	}
	
	return sz;
}

//##ModelId=431C34C7007D
void CTabManagerWindow::UpdateTabSize()
{
	CSize szTab = CalcTabsSize(SnapOrientations(cfg_iOrientation));
	
	m_iTabHeight = szTab.cy;
	m_iTabWidth  = szTab.cx;
}
